#include "QRenderTexture.h"
#include "QRenderUtility.h"

QRenderTexture::QRenderTexture()
{
    this->id = (unsigned int)0;
    this->unit = (unsigned int)0;
    this->target = (unsigned int)0;
    this->format = (unsigned int)0;
    this->type = (unsigned int)0;
    this->name.assign(std::string());
    this->size.assign(0, (unsigned int)0);
}

QRenderTexture::QRenderTexture(unsigned int id, unsigned int unit, unsigned int target, unsigned int format, unsigned int type, const std::string &name, const std::vector<unsigned int> &size)
{
    this->id = id;
    this->unit = unit;
    this->target = target;
    this->format = format;
    this->type = type;
    this->name = name;
    this->size = size;
}

QRenderTexture::~QRenderTexture()
{

}

void QRenderTexture::addTexture(std::vector<QRenderTexture> &textures, const std::string &name, const std::vector<unsigned int> &size, void *data, int internalFormat, unsigned int format, unsigned int type)
{
    unsigned int id = -1, unit = textures.size();
    unsigned int target = -1;
    glGenTextures(1, &id);
    int dimension = size.size();
    switch (dimension)
    {
    case 1:
        target = GL_TEXTURE_1D;
        glBindTexture(target, id);
        glTexImage1D(target, 0, internalFormat, size.at(0), 0, format, type, data);
        glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        break;
    case 2:
        target = GL_TEXTURE_2D;
        glBindTexture(target, id);
        glTexImage2D(target, 0, internalFormat, size.at(0), size.at(1), 0, format, type, data);
        glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
        break;
    case 3:
        target = GL_TEXTURE_3D;
        glBindTexture(target, id);
		unsigned char error;
		if (error = !QRenderUtility::checkError(__FILE__, __LINE__)) return;
        glTexImage3D(target, 0, internalFormat, size.at(0), size.at(1), size.at(2), 0, format, type, data);
		if (error = !QRenderUtility::checkError(__FILE__, __LINE__)) return;
        glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
        glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
        glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
        break;
    }
    
    QRenderTexture texture = QRenderTexture(id, unit, target, format, type, name, size);
    textures.push_back(texture);
}

void QRenderTexture::updateTexture(std::vector<QRenderTexture> &textures, int index, void *data)
{
    QRenderTexture *texture = &textures.at(index);
    unsigned int id = texture->id;
    unsigned int target = -1;
    int dimension = texture->size.size();
    switch (dimension)
    {
    case 1:
        target = GL_TEXTURE_1D;
        glBindTexture(target, id);
        glTexSubImage1D(target, 0, 0, texture->size.at(0), texture->format, texture->type, data);
        break;
    case 2:
        target = GL_TEXTURE_2D;
        glBindTexture(target, id);
        glTexSubImage2D(target, 0, 0, 0, texture->size.at(0), texture->size.at(1), texture->format, texture->type, data);
        break;
    case 3:
        target = GL_TEXTURE_3D;
        glBindTexture(GL_TEXTURE_3D, id);
        glTexSubImage3D(target, 0, 0, 0, 0, texture->size.at(0), texture->size.at(1), texture->size.at(2), texture->format, texture->type, data);
        break;
    }
}

int QRenderTexture::findTexture(std::vector<QRenderTexture> &textures, const char *name, int start)
{
    for (int i = start; i < textures.size(); i++)
    {
        if (textures.at(i).name.find(name) != std::string::npos) return i;
    }
    return -1;
}